/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.struct.table

import com.gitee.wsl.api.IFreezable
import com.gitee.wsl.func.Function
import com.gitee.wsl.func.predicate.Predicate
import com.gitee.wsl.struct.table.impl.SubTableView
import com.gitee.wsl.struct.table.utils.TableImpls
import kotlin.math.max

interface ITableView : IFreezable {
    val rowCount: Int

    val colCount: Int

    val isSingleCell: Boolean
        get() = rowCount == 1 && colCount == 1

    val headerCount: Int
        /**
         * 表头所占据的行数
         */
        get() = 0

    val sideCount: Int
        /**
         * 表旁所占据的行数
         */
        get() = 0

    val footerCount: Int
        /**
         * 表尾所占据的行数
         */
        get() = 0

    val id: String?

    val styleId: String?

    val cellRange: CellRange
        get() = CellRange(
            0,
            0,
            max(0, (rowCount - 1)),
            max(0, (colCount - 1))
        )

    val cols: List<IColumnConfig>

    fun getCol(colIndex: Int): IColumnConfig? {
        return cols[colIndex]
    }

    fun getColWidth(colIndex: Int): Double? {
        return getCol(colIndex)?.width
    }

    val rows: List<IRowView?>

    /**
     * 根据行下标返回行，如果对应的行不存在则返回null
     *
     * @param rowIndex 从0开始
     */
    fun getRow(rowIndex: Int): IRowView?

    /**
     * 根据行坐标和列坐标取到单元格。如果该位置被合并单元格占用，则返回ProxyCell
     *
     * @param rowIndex 行坐标
     * @param colIndex 列坐标
     * @return 有可能返回null, 对应空单元格
     */
    fun getCell(rowIndex: Int, colIndex: Int): ICellView? {
        return  getRow(rowIndex)?.getCell(colIndex)
    }

    fun getCellValue(rowIndex: Int, colIndex: Int): Any? {
        return getCell(rowIndex, colIndex)?.value
    }

    fun getCellText(rowIndex: Int, colIndex: Int): String? {
        return getCell(rowIndex, colIndex)?.text
    }

    fun isBlankRow(rowIndex: Int): Boolean {
        val row: IRowView? = getRow(rowIndex)
        return row == null || row.isBlankRow
    }

    fun getFirstRealCellInCol(colIndex: Int): ICellView? {
        for (row in this.rows) {
            if (row == null) continue
            val cell = row.getCell(colIndex)
            if (cell != null && !cell.isProxyCell) return cell
        }
        return null
    }

    fun <E : ICellView> forEachRealCell(processor: ICellProcessor<E>) {
        var i = 0
        val n = rowCount
        while (i < n) {
            val row: IRowView? = getRow(i)
            if (row == null) {
                i++
                continue
            }
            row.forEachRealCell<E>(i, processor)
            i++
        }
    }

    fun <E : ICellView> forEachCell(processor: ICellProcessor<E>) {
        var i = 0
        val n = rowCount
        while (i < n) {
            val row: IRowView? = getRow(i)
            if (row == null) {
                i++
                continue
            }
            row.forEachCell<E>(i, processor)
            i++
        }
    }

    /**
     * 将表格中的一个区域包装为ITable形式
     *
     * @param range 表格区间对象
     */
    fun getSubTable(range: CellRange): ITableView? {
        if (rowCount <= 0 || colCount <= 0) return null

        val tableRange = CellRange(0, 0, rowCount - 1, colCount - 1)
        val intersect: CellRange = tableRange.intersect(range) ?: return null
        return SubTableView(this, intersect)
    }

    fun getSubTable(
        firstRowIndex: Int,
        firstColIndex: Int,
        lastRowIndex: Int,
        lastColIndex: Int
    ): ITableView? {
        return getSubTable(CellRange(firstRowIndex, firstColIndex, lastRowIndex, lastColIndex))
    }

    fun isAllColumnCellSatisfy(
        colIndex: Int,
        predicate: Predicate<ICellView?>
    ): Boolean {
        return TableImpls.isAllColumnCellSatisfy(this, colIndex, predicate)
    }

    fun isSomeColumnCellSatisfy(
        colIndex: Int,
        predicate: Predicate<ICellView?>
    ): Boolean {
        return TableImpls.isSomeColumnCellSatisfy(this, colIndex, predicate)
    }

    fun isAllRowCellSatisfy(
        rowIndex: Int,
        predicate: Predicate<ICellView?>
    ): Boolean {
        return TableImpls.isAllRowCellSatisfy(this, rowIndex, predicate)
    }

    fun isSomeRowCellSatisfy(
        rowIndex: Int,
        predicate: Predicate<ICellView?>
    ): Boolean {
        return TableImpls.isSomeRowCellSatisfy(this, rowIndex, predicate)
    }

    fun <T> getMatrixValues( fn: Function<ICellView?, T>): List<List<T>> {
        return TableImpls.getMatrixValues(this, fn)
    }

    val matrixValues: List<List<Any?>>
        get() = getMatrixValues<Any?>(Function<ICellView?, Any?> { cell: ICellView? ->  cell?.value })

    /**
     * 根据headers中指定的列，返回单元格的值
     *
     * @param headers 对应返回的Map的key
     */
    fun <T> getRowValues(
        headers: List<String>,
        fn: Function<ICellView?, T>
    ): List<Map<String, T>> {
        return TableImpls.getRowValues(this, headers, fn)
    }

    fun getRowValues(headers: List<String>): List<Map<String, Any?>> {
        return getRowValues<Any?>(
            headers,
            Function<ICellView?, Any?> { cell: ICellView? ->  cell?.value })
    }

    fun checkAllowChange() {
        IFreezable.checkNotFrozen(this)
    }
}